package com.xu.cloud.common.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusPropertiesCustomizer;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
import com.xu.cloud.common.conditional.ExcludeProfile;
import com.xu.cloud.common.constant.EnvConstant;
import com.xu.cloud.common.mp.MysqlSqlInjector;
import com.xu.cloud.common.mybatis.SqlSessionFactoryLogging;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.List;

/**
 * ORM(Object-Relational Mapping)对象关系映射配置类
 *
 * @author xuguan
 * @since 2023/1/15
 */
@Configuration
@Slf4j
public class OrmConfig {

    @Configuration
    @ConditionalOnClass(value = {
            MybatisPlusAutoConfiguration.class,
            MybatisPlusInterceptor.class
    })
    public static class MybatisPlusConfig {

        /**
         * 设置 MySql SQL注入器
         */
        @Bean
        @ConditionalOnMissingBean
        public MybatisPlusPropertiesCustomizer mybatisPlusPropertiesCustomizer(DataSource dataSource) {
            try {
                final String jdbcUrl = dataSource.getConnection().getMetaData().getURL();
                final DbType dbType = JdbcUtils.getDbType(jdbcUrl);
                if (DbType.MYSQL.equals(dbType)) {
                    return new MybatisPlusPropertiesCustomizer() {
                        @Override
                        public void customize(MybatisPlusProperties properties) {
                            properties.getGlobalConfig().setSqlInjector(new MysqlSqlInjector());
                        }
                    };
                }
            } catch (SQLException e) {
                // ignore
            }
            return null;
        }

        /**
         * mybatis plus插件配置
         */
        @Bean
        @ConditionalOnMissingBean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            // 引入分页插件
            PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
            // 设置请求的页面大于最大页后的操作, true调回到首页, false继续请求
            paginationInnerInterceptor.setOverflow(true);
            // 设置最大单页数量限制
            paginationInnerInterceptor.setMaxLimit(1000L);
            interceptor.addInnerInterceptor(paginationInnerInterceptor);

            return interceptor;
        }


        /**
         * 自定义实现mybatis自动填充创建时间和修改时间
         */
        @Bean
        @ConditionalOnMissingBean
        public MetaObjectHandler metaObjectHandler() {
            return new MetaObjectHandler() {
                @Override
                public void insertFill(MetaObject metaObject) {
                    log.info("start insert fill ....");
                    this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
                    this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
                }

                @Override
                public void updateFill(MetaObject metaObject) {
                    log.info("start update fill ....");
                    this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
                }
            };
        }

    }

    @Configuration
    @ConditionalOnClass(value = {
            SqlSession.class,
            SqlSessionFactory.class,
    })
    @ConditionalOnBean(value = {
            SqlSessionFactory.class,
    })
    public static class MybatisConfig {

        /**
         * mybatis日志拦截器配置
         */
        @ExcludeProfile(EnvConstant.PROD)
        @Bean
        @ConditionalOnMissingBean(name = "sqlSessionFactoryLogging")
        @ConditionalOnProperty(prefix = "mybatis.logging", name = "enable", havingValue = "true", matchIfMissing = true)
        public SqlSessionFactoryLogging sqlSessionFactoryLogging(List<SqlSessionFactory> sqlSessionFactoryList) {
            return new SqlSessionFactoryLogging(sqlSessionFactoryList);
        }

    }

}
